package com.sea.app.module.process.domain.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sea.app.common.excrption.BusinessException;
import com.sea.app.common.excrption.SystemException;
import com.sea.app.common.kit.Strings;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.ZipInputStream;

/**
 * Created by 31417 on 2017/4/30.
 */
@Service
public class RepositoryDeployService {

    @Autowired
    RepositoryService repositoryService;


    public void deploy(String category, MultipartFile file) {
        Deployment deployment = null;
        try {
            InputStream fileInputStream = file.getInputStream();
            Strings fileName = Strings.on(file.getOriginalFilename());
            if(fileName.endWith(".zip")||fileName.endWith(".bar")){
                deployment = deployZIP(fileInputStream);
            }
            if(fileName.endWith(".bpmn20.xml")){
                deployment = deployInputStream(fileName.toString(),fileInputStream);
            }
            if(fileName.endWith(".bpmn")){
                deployment = deployInputStream(fileName
                                .removeEnd(".bpmn".length())
                                .joinEnd(".bpmn20.xml")
                                .toString()
                        ,fileInputStream);
            }
            if (deployment == null){
                throw BusinessException.on("activiti.modelDeploymentFail","不支持的文件格式："+file.getOriginalFilename());
            }
            // 设置流程分类
            List<ProcessDefinition> list = findProcessDefinitionByDeploymentId(deployment.getId());
            if (list.size() == 0){
                throw BusinessException.on("activiti.modelDeploymentFail","流程部署失败："+deployment.getId());
            }
            setProcessDefinitionsCategory(list,category);

        } catch (Exception e) {
            throw SystemException.on(e);
        }
    }

    /**
     * 激活流程
     * @param procDefId
     */
    public void activateDefinition(String procDefId) {
        repositoryService.activateProcessDefinitionById(procDefId, true, null);
    }

    /**
     * 挂起流程
     * @param procDefId
     */
    public void suspendDefinition(String procDefId) {
        repositoryService.suspendProcessDefinitionById(procDefId, true, null);
    }
    private Deployment deployZIP(InputStream inputStream){
        return repositoryService.createDeployment().addZipInputStream(new ZipInputStream(inputStream)).deploy();
    }
    private Deployment deployInputStream(String name,InputStream inputStream){
        return repositoryService.createDeployment().addInputStream(name, inputStream).deploy();
    }
    /**
     *部署模型
     * @param modelId
     */
    public void deploy(String modelId) {
        try {
            org.activiti.engine.repository.Model modelData = repositoryService.getModel(modelId);
            ByteArrayInputStream in = bpmnModelToByteArrayInputStream(getBpmnModelByModel(modelData));
            Strings processName = Strings.on(modelData.getName()).defaultString("def").mustSuffix(".bpmn20.xml");

            Deployment deployment = repositoryService.createDeployment().name(modelData.getName())
                    .addInputStream(processName.toString(), in).deploy();
            // 设置流程分类
            List<ProcessDefinition> list = findProcessDefinitionByDeploymentId(deployment.getId());
            if (list.size() == 0){
                throw BusinessException.on("activiti.modelDeploymentFail","流程部署失败："+deployment.getId());
            }
            setProcessDefinitionsCategory(list,modelData.getCategory());
        } catch (Exception e) {
            throw SystemException.on(e);
        }
    }
    //
    private List<ProcessDefinition> findProcessDefinitionByDeploymentId(String deploymentId){
        return repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).list();
    }
    //设置流程种类
    private void setProcessDefinitionsCategory(List<ProcessDefinition> list,String category){
        for (ProcessDefinition processDefinition : list) {
            updateCategory(processDefinition.getId(), category);
        }
    }
    public void updateCategory(String procDefId, String category) {
        repositoryService.setProcessDefinitionCategory(procDefId, category);
    }


    //模型转换为流
    private ByteArrayInputStream bpmnModelToByteArrayInputStream(BpmnModel bpmnModel){
        BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
        byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);
        return new ByteArrayInputStream(bpmnBytes);
    }
    //获取模型的BpmnMode
    private BpmnModel getBpmnModelByModel(Model modelData){
        try {
            BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
            JsonNode editorNode = new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
            return jsonConverter.convertToBpmnModel(editorNode);
        }catch (Exception e){
            throw SystemException.on(e);
        }
    }
    /**
     * 导出model的xml文件
     */
    public void export(String id, OutputStream outputStream) {
        try {
            org.activiti.engine.repository.Model modelData = repositoryService.getModel(id);
            BpmnModel bpmnModel = getBpmnModelByModel(modelData);
            ByteArrayInputStream in = bpmnModelToByteArrayInputStream(bpmnModel);
            String filename = bpmnModel.getMainProcess().getId() + ".bpmn20.xml";
            IOUtils.copy(in, outputStream);
        } catch (Exception e) {
            throw SystemException.on(e);
        }

    }

    /**
     * 删除部署
     * @param deploymentId
     */
    public void deleteDeployment(String deploymentId) {
        repositoryService.deleteDeployment(deploymentId, true);
    }
}
